// ----------------------------------------------------------------------------
// string_proxy.h
// ----------------------------------------------------------------------------
/*
 Description:
 実行環境ごとに異なる文字列操作関数の代替関数を提供する.
 
 ----------------------------------------------------------------
 使い方.
 
 各関数のコメントを参照して下さい. 
 */
#pragma once
#include <fw/base/core/macros.h>
#include <fw/base/core/stdinteger.h>
#include <fw/base/core/assertion.h>
#include <alloca.h>
#include <stdarg.h>
#include <cstring>
#include <string>

namespace fw
{
	/**
	 * 大文字小文字を区別しない文字列比較を行う.
	 *
	 * @param str1   [in]  最初の文字列.
	 * @param str2   [in]  次の文字列.
	 *
	 * @return str1がstr2より小さい場合は負の値、str1がstr2より大きい場合は性の値、同じ場合は0を返します.
	 */
	FW_FORCE_INLINE int32_t stricmp(const char* str1, const char* str2)
	{
		FW_ASSERT(str1);
		FW_ASSERT(str2);
	#if   USING(FW_COMPILER_MSC) || USING(FW_COMPILER_MSVC)
		return _stricmp(str1, str2);
	#elif USING(FW_COMPILER_GCC) || USING(FW_COMPILER_CLANG)
		return strcasecmp(str1, str2);
	#else
		#error	 "未対応のプラットフォームです."
	#endif
	}
	
	/**
	 * 文字列長制限つきで文字列中から文字列を検索する.
	 *
	 * @param str    [in]  検索対象文字列.
	 * @param find   [in]  検索文字列.
	 * @param size   [in]  検索する範囲の文字列長.
	 *
	 * @return 文字列が見つかった場合一致した文字列のアドレス、見つからなかった場合はnullptrを返します.
	 */
	FW_FORCE_INLINE const char* strnstr(const char* str, const char* find, size_t size)
	{
		if(!str)
		{
			return nullptr;
		}
		if(!find)
		{
			return str;
		}
		
		char first = *find;
		if(first == '\0')
		{
			return str;
		}
		
		const char* cmp = find + 1;
		size_t len = strlen(cmp);
		do
		{
			// 最初の一文字がマッチしてから残りの文字列を比較する.
			for(char match=*str++; match!=first && 0<size; match=*str++, --size)
			{
				if(match=='\0')
				{
					return nullptr;
				}
			}
			if(size==0)
			{
				return nullptr;
			}
		} while(strncmp(str, cmp, len)!=0);
		return --str;
	}
	
} // namespace fw

#define FW_STRICMP(a,b)		fw::stricmp(a,b)
#define FW_STRNSTR(s,f,n)	fw::strnstr(s,f,n)
